import os
import psycopg2
import sys
import time
import uuid

if sys.modules.has_key('_apache'):
	from mod_python import apache, Cookie, util, Session

try:
	import config
	dbName = config.dbName
	production = config.production
except:
	print "You need a config.py in the modules directory."
	print
	print "dbName = 'opendb'"
	print "production = False"
	print
	sys.exit()




def GetDBConnection():
	global dbConnection
	try:
		return dbConnection
	except NameError:
		try:
			import psycopg2
			dbConnection = psycopg2.connect(database='%s' % (dbName))
			return dbConnection
		except StandardError, errmsg:
			return None



def LogError(message="-------------------"):
	message = "----- " + " : " + str(message)
	if sys.modules.has_key('_apache'):
		from mod_python import apache
		apache.log_error(message)
	else:
		print message




# Location
#######################################################################

class Location(object):
	def __init__(self, id=''):
		dbConnection = GetDBConnection()
		cursor = dbConnection.cursor()
		self.error = ''

		self.parent = ''
		self.engName = ''
		self.afrName = ''
		self.postalCodeStreet = ''
		self.postalStreetDefault = False
		self.postalCodeBox = ''
		self.postalBoxDefault = False
		self.siblings = []
		self.children = []
		self.id = id


		cursor.execute("""SELECT parent, eng_name, afr_name, postal_code_street, postal_street_default, postal_code_box, postal_box_default FROM locations WHERE id = %s""", (self.id,))
		if cursor.rowcount:
			(self.parent, self.engName, self.afrName, self.postalCodeStreet, self.postalStreetDefault, self.postalCodeBox, self.postalBoxDefault) = cursor.fetchone()

		if self.id:
			cursor.execute("""SELECT id FROM locations WHERE (parent = %s) AND (id != %s)""", (self.parent, self.id))
			for record in cursor.fetchall():
				(sibling, ) = record
				self.siblings.append(sibling)

		cursor.execute("""SELECT id FROM locations WHERE parent = %s ORDER BY eng_name""", (self.id,))
		for record in cursor.fetchall():
			(child, ) = record
			self.children.append(child)



	def Save(self):
		dbConnection = GetDBConnection()
		cursor = dbConnection.cursor()
		if not self.id:
			self.error = "No ID defined."
			return False
		if not self.engName:
			self.error = "You need to have an engName for this location."
			return False

		cursor.execute("""SELECT 1 FROM locations WHERE id = %s""", (self.id,))
		if cursor.rowcount:
			cursor.execute("""UPDATE locations SET parent = %s, eng_name = %s, afr_name = %s, postal_code_street = %s, postal_code_box = %s
				WHERE id = %s""",
				(self.parent, self.engName, self.afrName, self.postalCodeStreet, self.postalCodeBox, self.id))
			dbConnection.commit()
			return True
		else:
			cursor.execute("""INSERT INTO locations (id, parent, eng_name, afr_name, postal_code_street, postal_code_box)
				VALUES (%s, %s, %s, %s, %s, %s)""",
				(self.id, self.parent, self.engName, self.afrName, self.postalCodeStreet, self.postalCodeBox))
			dbConnection.commit()
			return True




	def AddChild(self, engName, postalCodeStreet='', postalCodeBox=''):
		dbConnection = GetDBConnection()
		cursor = dbConnection.cursor()
		if not self.id:
			return False
		cursor.execute("SELECT id FROM locations WHERE (eng_name = %s) AND (parent = %s)", (engName, self.id))
		if cursor.rowcount:
			self.error = "The location already exists."
			return False
		else:
			newLocation = Location(str(uuid.uuid4()))
			newLocation.parent = self.id
			newLocation.engName = engName
			newLocation.postalCodeStreet = postalCodeStreet
			newLocation.postalCodeBox = postalCodeBox
			if newLocation.Save():
				self.children.append(newLocation.id)
				return True
			else:
				self.error = "Add Child failed"
				return False



def UpdateLocationID(oldID, newID):
	if not oldID:
		return (False, 'No old ID provided')

	if not newID:
		return (False, 'No new ID provided')
	
	dbConnection = GetDBConnection()
	cursor = dbConnection.cursor()


	cursor.execute('SELECT eng_name FROM locations WHERE id = %s', (newID, ))
	if cursor.rowcount:
		(name, ) = cursor.fetchone()
		return (False, 'ID %s is already used by %s' % (newID, name))

	else:
		cursor.execute("UPDATE locations SET parent = %s WHERE parent = %s", (newID, oldID))
		cursor.execute("UPDATE locations SET id = %s WHERE id = %s", (newID, oldID))
		dbConnection.commit()
		return (True, '')




class Ticket(object):
	def __init__(self, id=0):
		self.id = id
		self.locationID = ''
		self.message = ''
		self.reportBy = ''
		self.reportDate = None
		self.completeBy = ''
		self.completeDate = None
		self.done = False

		cursor = GetDBConnection().cursor()
		cursor.execute("""SELECT location_id, message, report_by, report_date, complete_by, complete_date, done
			FROM tickets WHERE id = %s """, (self.id,))
		if cursor.rowcount:
			(self.locationID, self.message, self.reportBy, self.reportDate, self.completeBy, self.completeDate, self.done) = cursor.fetchone()


	def Save(self):
		dbConnection = GetDBConnection()
		cursor = dbConnection.cursor()

		cursor.execute("SELECT 1 FROM tickets WHERE id = %s", (self.id,))
		if cursor.rowcount:
			cursor.execute("""UPDATE tickets SET complete_by = %s, complete_date = %s, done = %s
				WHERE id = %s""", (self.completeBy, self.completeDate, self.done, self.id, ))
			dbConnection.commit()
		else:
			cursor.execute("""INSERT INTO tickets (message, location_id, report_by) VALUES (%s, %s, %s)""",
				(self.message, self.locationID, self.reportBy, ))
			dbConnection.commit()



# Users
#######################################################################

class User(object):
	def __init__(self, openID=''):
		self.openID = openID
		self.name = ''
		self.email = ''
		self.admin = False
		self.active = False

		if not self.openID:
			return

		dbConnection = GetDBConnection()
		cursor = dbConnection.cursor()
		cursor.execute("""SELECT name, email, admin, active FROM users WHERE openid = %s""", (self.openID, ))
		if cursor.rowcount:
			(self.name, self.email, self.admin, self.active) = cursor.fetchone()
			if not self.name:
				self.name = "Unknown User"
			return
		else:
			cursor.execute("""INSERT INTO users (openid) VALUES (%s)""", (self.openID, ))
			dbConnection.commit()

			# If running as dev, make the first user to log in an administrator
			if not production:
				cursor.execute("""SELECT openid FROM users""")
				if cursor.rowcount == 1:
					cursor.execute("""UPDATE users SET admin = TRUE""")
					dbConnection.commit()


	def Save(self):
		dbConnection = GetDBConnection()
		cursor = dbConnection.cursor()
		cursor.execute("""UPDATE users SET name = %s, email = %s, admin = %s, active = %s WHERE openid = %s""", (self.name, self.email, self.admin, self.active, self.openID, ))
		dbConnection.commit()



# Web
#######################################################################

class Web(object):
	def __init__(self, req):
		self.req = req

		self.timeout = 28800
		self.startTime = time.time()

		self.cookies = Cookie.get_cookies(req)
		self.session = Session.Session(req, timeout=self.timeout, lock=False)
		self.session.save()

		self.SetCookie('pysid', str(self.session.id()))

		self.CheckAuth()




	def Write(self, output=""):
		self.req.write(str(output))
		self.req.write("\n")



	def GetData(self, field):
		try:
			self.req.form
		except:
			self.req.form = util.FieldStorage(self.req)

		try:
			return self.req.form[field].strip()
		except:
			return ''



	def GetNumber(self, field):
		try:
			self.req.form
		except:
			self.req.form = util.FieldStorage(self.req)

		if self.req.form.has_key(field):
			fieldVal = self.req.form[field].strip()
			if fieldVal.isdigit():
				return int(fieldVal)
		return 0



	def Header(self, title='The Open Database for South African'):
		self.req.content_type = "text/html; charset=utf-8"
		self.Write("""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">""")
		self.Write("""<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">""")
		self.Write("""<head>""")
		self.Write("""<title>%s</title>""" % (title))
		self.Write("""<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />""")
		self.Write("""<meta name="description" content="The Open Database for South African" />""")
		self.Write("""<meta name="keywords" content="public holidays, postal codes" />""")
		self.Write("""<link rel="stylesheet" href="/includes/default.css" type="text/css" media="screen,projection" />""")
		self.Write("""</head>""")
		self.Write("""<body>""")
		self.Write("""<div id="container" >""")

		self.Write("""<div id="header">""")
		self.Write("""<a href="/">The Open Database</a>""")
		self.Write("""<p>Postal codes and Public Holidays for your apps. More to come.</p>""")
		self.Write("""</div>""")

		self.Write("""<div id="topmenu">""")
		self.Write("""<ul>""")
		self.Write("""<li><a href="/">Home</a></li>""")
		self.Write("""<li><a href="/public-holidays/">Public Holidays</a></li>""")
		self.Write("""<li><a href="/locations/">Locations</a></li>""")
		if self.user.admin:
			self.Write("""<li><a href="/locations/tickets.py">Location Tickets</a></li>""")
		self.Write("""<li><a href="/downloads.py">Downloads</a></li>""")
		self.Write("""<li><a href="/contact.py">Contact</a></li>""")
		if self.user.openID:
			self.Write("""<li><a href="/auth/prefs.py">%s</a></li> """ % (self.user.name))
			self.Write("""<li><a href="/auth/prefs.py?logout=1">Log Out</a></li>""")
		else:
			self.Write("""<li><a href="/auth/">Log In</a></li>""")
		self.Write("""<li><a href="/search.py">Search</a></li>""")

		self.Write("""</ul>""")
		self.Write("""</div>""")
		self.Write("""<div id="content">""")



	def Footer(self):
		self.Write(""" </div>""")
		self.Write(""" <div id="footer">""")
		self.Write(""" All content available under a <a href="http://creativecommons.org/licenses/by-sa/2.5/za/">Creative Commons Attribution-Share Alike 2.5 South Africa License</a> """)
		self.Write(""" </div>""")
		self.Write(""" </div>""")
		self.Write(""" </body>""")
		self.Write(""" </html>""")



	def Redirect(self, page='/'):
		self.req.headers_out['location'] = '%s' % (page)
		self.req.status = apache.HTTP_MOVED_TEMPORARILY


	def SetSession(self, name, value):
		self.session[name] = value
		self.session.save()



	def GetSession(self, name):
		self.session.load()
		if self.session.has_key(name):
			return self.session[name]
		else:
			return ''



	def SetCookie(self, name, value):
		cookie = Cookie.Cookie(name, str(value), path='/')
		cookie.expires = time.time() + (self.timeout)
		Cookie.add_cookie(self.req, cookie)



	def GetCookie(self, name):
		try:
			return str(self.cookies[name].value.strip())
		except:
			return ''



	def ReAuth(self):
		newKey = str(uuid.uuid4())
		self.SetSession('key', newKey)
		self.SetCookie('key', newKey)
		self.SetSession('last_auth', time.time())
		self.SetSession('openid', self.user.openID)



	def CheckAuth(self):
		if self.GetSession('key') and self.GetCookie('key'):
			if str(self.GetSession('key')) == str(self.GetCookie('key')):
				openID = self.GetSession('openid')
				self.user = User(openID)
				return True
		self.user = User()
		self.SetSession('user_id', 0)
		self.SetSession('key', 0)
		self.SetCookie('key', 0)
		return False


